package com.cosw.util;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DesTools {
	private static final String CIPHER_ALGORITHM_3DES_ECB_NOPADDING = "DESede/ECB/NoPadding";
	private static final String CIPHER_ALGORITHM_3DES_CBC_NOPADDING = "DESede/CBC/NoPadding";

	private static final String CIPHER_ALGORITHM_DES_ECB_NOPADDING = "DES/ECB/NoPadding";
	private static final String CIPHER_ALGORITHM_DES_CBC_NOPADDING = "DES/CBC/NoPadding";

	private static final String ALGORITHM_3DES = "DESede"; // 定义加密算法,可用
	private static final String ALGORITHM_DES = "DES"; // 定义加密算法,可用

	private static final byte[] PADDING_8000S = { (byte) 0x80, (byte) 0x00,
			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
			(byte) 0x00 };

	private static final byte[] PADDING_0000S = { (byte) 0x00, (byte) 0x00,
			(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
			(byte) 0x00 };

	/**
	 * 强制补800000000000(8的倍数也补);
	 * 
	 * @param s
	 * @return
	 */
	private static byte[] bytesPadding8000s(byte[] s) {
		byte[] res = new byte[s.length + (8 - s.length % 8)];
		StringUtil.byteArrayCopy(s, 0, res, 0, s.length);
		StringUtil.byteArrayCopy(PADDING_8000S, 0, res, s.length,
				(8 - (s.length % 8)));
		return res;
	}

	/**
	 * 强制补000000000000(8的倍数也补);
	 * 
	 * @param s
	 * @return
	 */
	private static byte[] bytesPadding0000s(byte[] s) {
		byte[] res = new byte[s.length + (8 - s.length % 8)];
		StringUtil.byteArrayCopy(s, 0, res, 0, s.length);
		StringUtil.byteArrayCopy(PADDING_0000S, 0, res, s.length,
				(8 - (s.length % 8)));
		return res;
	}

	public static byte[] initialKeyByte(byte[] key) {
		byte[] keyByte;

		if (key.length == 16) {
			keyByte = new byte[24];

			StringUtil.byteArrayCopy(key, 0, keyByte, 0, 16);
			StringUtil.byteArrayCopy(key, 0, keyByte, 16, 8);
		} else {
			keyByte = key;
		}

		return keyByte;
	}

	/**
	 * 3Des-ECB加密，调用前先padding
	 * 
	 * @param keybyte
	 *            : 24字节
	 * @param src
	 * @return
	 */
	public static byte[] encryptBy3DesECBNoPadding(byte[] key, byte[] src) {
		try {
			byte[] keyByte = initialKeyByte(key);

			// 生成密钥
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_3DES);
			// 加密
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_3DES_ECB_NOPADDING);
			c1.init(Cipher.ENCRYPT_MODE, deskey);
			return c1.doFinal(src);// 在单一方面的加密或解密
		} catch (java.security.NoSuchAlgorithmException e1) {
			// TODO: handle exception
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * 3Des-ecb解密
	 * 
	 * @param keybyte
	 *            24字节
	 * @param src
	 * @return
	 */
	public static byte[] decryptBy3DesECBNoPadding(byte[] key, byte[] src) {
		try {
			byte[] keyByte = initialKeyByte(key);

			// 生成密钥
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_3DES);
			// 解密
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_3DES_ECB_NOPADDING);
			c1.init(Cipher.DECRYPT_MODE, deskey);
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			// TODO: handle exception
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * 3DES-CBC 加密, noPAdding;
	 * 
	 * @param key
	 * @param src
	 * @param ivs
	 * @return
	 */
	public static byte[] encryptBy3DesCBCNoPadding(byte[] key, byte[] src,
			byte[] ivs) {
		try {
			byte[] keyByte = initialKeyByte(key);

			IvParameterSpec iv = new IvParameterSpec(ivs);
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_3DES); // 生成密钥21
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_3DES_CBC_NOPADDING); // 实例化负责加密/解密的Cipher工具类22
			c1.init(Cipher.ENCRYPT_MODE, deskey, iv); // 初始化为加密模式23
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * 3DES-CBC 解密, noPAdding;
	 * 
	 * @param key
	 * @param src
	 * @param ivs
	 * @return
	 */
	public static byte[] decryptBy3DesCBCNoPadding(byte[] key, byte[] src,
			byte[] ivs) {
		try {
			byte[] keyByte = initialKeyByte(key);

			IvParameterSpec iv = new IvParameterSpec(ivs);
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_3DES);
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_3DES_CBC_NOPADDING);
			c1.init(Cipher.DECRYPT_MODE, deskey, iv); // 初始化为解密模式44
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * DES-ECB NoPadding 加密
	 * 
	 * @param key
	 * @param src
	 * @return
	 */
	public static byte[] encryptByDesECBNoPadding(byte[] key, byte[] src) {
		try {
			SecretKeySpec desKey = new SecretKeySpec(key, ALGORITHM_DES);
			Cipher cipher = Cipher
					.getInstance(CIPHER_ALGORITHM_DES_ECB_NOPADDING);
			cipher.init(Cipher.ENCRYPT_MODE, desKey);
			return cipher.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;

	}

	/**
	 * DES-ECB NoPadding解密
	 * 
	 * @param key
	 * @param src
	 * @return
	 */
	public static byte[] decryptByDesECBNoPadding(byte[] key, byte[] src) {
		try {
			SecretKeySpec desKey = new SecretKeySpec(key, ALGORITHM_DES);
			Cipher cipher = Cipher
					.getInstance(CIPHER_ALGORITHM_DES_ECB_NOPADDING);
			cipher.init(Cipher.DECRYPT_MODE, desKey);
			return cipher.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * DES-CBC 加密, noPAdding;
	 * 
	 * @param key
	 * @param src
	 * @param ivs
	 * @return
	 */
	public static byte[] encryptByDesCBCNoPadding(byte[] keyByte, byte[] src,
			byte[] ivs) {
		try {
			IvParameterSpec iv = new IvParameterSpec(ivs);
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_DES); // 生成密钥21
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_DES_CBC_NOPADDING); // 实例化负责加密/解密的Cipher工具类22
			c1.init(Cipher.ENCRYPT_MODE, deskey, iv); // 初始化为加密模式23
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * DES-CBC 解密, noPAdding;
	 * 
	 * @param key
	 * @param src
	 * @param ivs
	 * @return
	 */
	public static byte[] decryptByDesCBCNoPadding(byte[] keyByte, byte[] src,
			byte[] ivs) {
		try {
			IvParameterSpec iv = new IvParameterSpec(ivs);
			SecretKey deskey = new SecretKeySpec(keyByte, ALGORITHM_DES);
			Cipher c1 = Cipher.getInstance(CIPHER_ALGORITHM_DES_CBC_NOPADDING);
			c1.init(Cipher.DECRYPT_MODE, deskey, iv); // 初始化为解密模式44
			return c1.doFinal(src);
		} catch (java.security.NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (javax.crypto.NoSuchPaddingException e2) {
			e2.printStackTrace();
		} catch (java.lang.Exception e3) {
			e3.printStackTrace();
		}
		return null;
	}

	/**
	 * 前面descbc,最后一块3DES;
	 * 
	 * @param keyByte
	 *            : 双倍长16字节;
	 * @param src
	 * @param ivs
	 * @return
	 */
	public static byte[] desPlusFinalTripleDes(byte[] keyByte, byte[] src,
			byte[] ivs) {

		byte[] keyLeft = new byte[8];
		byte[] keyRight = new byte[8];
		StringUtil.byteArrayCopy(keyByte, 0, keyLeft, 0, 8);
		StringUtil.byteArrayCopy(keyByte, 8, keyRight, 0, 8);

		// 自动padding 8000000000;
		byte[] source = bytesPadding8000s(src);
		// 前面des-cbc
		byte[] res = encryptByDesCBCNoPadding(keyLeft, source, ivs);

		// 右边key des解密;
		byte[] res1 = decryptByDesECBNoPadding(keyRight,
				StringUtil.subBytes(res, (short) (res.length - 8), (byte) 0x08));

		// 左边key des加密
		return encryptByDesECBNoPadding(keyLeft, res1);
	}
}
